# -*- coding: utf-8 -*-
"""
Created on 2024/11/27 22:19
@author: 江中新
"""

# https://www.geetest.com/demo/slide-float.html

import time
from loguru import logger
import execjs
import re
from PIL import Image
import slide
import ddddocr
from curl_cffi import requests
import random
from concurrent.futures import ProcessPoolExecutor

# session = requests.Session()


class GeetestSlide:
    def __init__(self):
        self.ctx = None
        self.register_slide_url = None
        self.gettype_url = None
        self.challenge = None
        self.gt = None
        self.w1 = None
        self.w2 = None
        self.w3 = None
        self.aes_key = None
        self.new_challenge = None
        self.c1 = None
        self.s1 = None
        self.c = None
        self.s = None
        self.bg = None
        self.slice = None
        self.distance = None
        self.slide_track = None
        self.pass_time = None
        self.enctrack = None
        self.headers = {
            'accept': 'application/json, text/javascript, */*; q=0.01',
            'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8',
            'cache-control': 'no-cache',
            'pragma': 'no-cache',
            'priority': 'u=1, i',
            'referer': 'https://www.geetest.com/demo/slide-float.html',
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
        }

    def read_js(self):
        with open('./start.js', 'r', encoding='utf-8') as f:
            self.ctx = execjs.compile(f.read())
        logger.success("js读取成功")

    def get_w1(self):
        data = self.ctx.call('get_w1', self.gt, self.challenge)
        self.w1 = data['w']
        self.aes_key = data['aes_key']

    def get_w2(self):
        self.w2 = self.ctx.call('get_w2', self.gt, self.challenge, self.aes_key, self.c1, self.s1)

    def get_w3(self):
        self.w3 = self.ctx.call('get_w', self.distance, self.enctrack, self.new_challenge, self.new_challenge[0:32],
                                self.pass_time, str(random.randint(100, 200)), self.gt)

    def register_slide(self):
        self.register_slide_url = "https://demos.geetest.com/gt/register-slide"
        params = {
            't': str(round(time.time() * 1000))
        }
        response = requests.get(self.register_slide_url, params=params, headers=self.headers)
        # print(response.text)
        self.challenge = response.json()["challenge"]
        self.gt = response.json()["gt"]
        # logger.debug("challenge: {}".format(self.challenge))
        # logger.debug("gt: {}".format(self.gt))

    def gettype(self):
        self.gettype_url = "https://apiv6.geetest.com/gettype.php"
        params = {
            'gt': self.gt,
            'callback': 'geetest_' + str(round(time.time() * 1000))
        }
        requests.get(self.gettype_url, params=params, headers=self.headers)
        # logger.info("response: {}".format(response.text))  # TODO: {"slide": 103, "click3": 128, "voice": 128, "beeline": 50}

    def get_php(self):
        """
        w1
        :return:
        """
        self.get_w1()  # self.w1
        # logger.info(f"w1: {self.w1}, len: {len(str(self.w1))}")  # 1516
        url = "https://apiv6.geetest.com/get.php"
        params = {
            "gt": self.gt,
            "challenge": self.challenge,
            "lang": "zh-cn",
            "pt": "0",
            "client_type": "web",
            "w": self.w1,
            "callback": "geetest_" + str(round(time.time() * 1000))
        }
        # time.sleep(0.5)
        response = requests.get(url, headers=self.headers, params=params)
        # print(f"get_php_response--> {response.content.decode('utf-8').encode('latin1').decode('unicode_escape')}")
        self.c1 = re.findall(r'"c": (.*?), "s', response.text)[0]
        self.s1 = re.findall(r'"s": "(.*?)", ', response.text)[0]
        # logger.debug(f"c1: {self.c1}, s1: {self.s1}")

    def ajax_php(self):
        """
        w2
        :return:
        """
        self.get_w2()  # self.w2
        # logger.info(f"w2: {self.w2}, len: {len(str(self.w2))}")  # 长度固定，看鼠标轨迹
        url = "https://api.geetest.com/ajax.php"
        params = {
            "gt": self.gt,
            "challenge": self.challenge,
            "lang": "zh-cn",
            "pt": "0",
            "client_type": "web",
            "w": self.w2,
            "callback": "geetest_" + str(round(time.time() * 1000))
        }
        # time.sleep(0.5)
        response = requests.get(url, headers=self.headers, params=params)
        # print(f"ajax_php_response--> {response.content.decode('utf-8').encode('latin1').decode('unicode_escape')}")

    def restore_picture(self):
        img_list = ["./乱序缺口背景图.png"]
        for index, img in enumerate(img_list):
            image = Image.open(img)
            s = Image.new("RGBA", (260, 160))
            ut = [39, 38, 48, 49, 41, 40, 46, 47, 35, 34, 50, 51, 33, 32, 28, 29, 27, 26, 36, 37, 31, 30, 44, 45, 43,
                  42,
                  12, 13, 23, 22, 14, 15, 21, 20, 8, 9, 25, 24, 6, 7, 3, 2, 0, 1, 11, 10, 4, 5, 19, 18, 16, 17]
            height_half = 80
            for inx in range(52):
                c = ut[inx] % 26 * 12 + 1
                u = height_half if ut[inx] > 25 else 0
                l_ = image.crop(box=(c, u, c + 10, u + 80))
                s.paste(l_, box=(inx % 26 * 10, 80 if inx > 25 else 0))
            s.save("./还原后的缺口背景图片.png")

    def save_pic(self):
        host_url = 'https://static.geetest.com/'
        slice_url = f"{host_url}{self.slice}"  # 不需要还原
        bg_url = f"{host_url}{self.bg}"  # TODO: 还原
        # logger.info(f"slice_url: {slice_url}, bg_url: {bg_url}")
        response = requests.get(slice_url)
        with open('./小滑块.png', 'wb') as f:
            f.write(response.content)
        response = requests.get(bg_url)
        with open('./乱序缺口背景图.png', 'wb') as f:
            f.write(response.content)
        self.restore_picture()

    # ddddocr 识别
    def slide_verify(self, slide_image, background_image):
        slide = ddddocr.DdddOcr(det=False, ocr=False, show_ad=False)
        result = slide.slide_match(slide_image, background_image, simple_target=True)
        return result['target'][0]

    def get_php_more_content(self):
        url = "https://api.geetest.com/get.php"
        params = {
            "is_next": "true",
            "type": "slide3",
            "gt": self.gt,
            "challenge": self.challenge,
            "lang": "zh-cn",
            "https": "true",
            "protocol": "https://",
            "offline": "false",
            "product": "embed",
            "api_server": "api.geevisit.com^",
            "isPC": "true",
            "autoReset": "true",
            "width": "100%",
            "callback": "geetest_" + str(round(time.time() * 1000))
        }
        response = requests.get(url, headers=self.headers, params=params)
        # print(
            # f"get_php_more_content_response--> {response.content.decode('utf-8').encode('latin1').decode('unicode_escape')}")
        self.c = re.findall(r'"c": (.*?), "s', response.text)[0]
        self.s = re.findall(r'"s": "(.*?)", "so', response.text)[0]
        self.bg = re.findall(r'"bg": "(.*?)",', response.text)[0]
        self.slice = re.findall(r'"slice": "(.*?)",', response.text)[0]
        self.new_challenge = re.findall(r'"challenge": "(.*?)",', response.text)[0]  # TODO: 会多两位
        # logger.debug(
        #     f"c: {self.c}, s: {self.s}, bg: {self.bg}, slice: {self.slice}, new_challenge: {self.new_challenge}")

        self.save_pic()  # 保存图片并且还原底图

        with open('./小滑块.png', 'rb') as f:
            slide_image = f.read()
        with open('./还原后的缺口背景图片.png', 'rb') as f:
            background_image = f.read()

        # TODO: 识别distance生成轨迹
        self.distance = int(self.slide_verify(slide_image, background_image)) - 4
        # logger.debug(f"distance: {self.distance}")

        self.slide_track = slide.get_slide_track(self.distance)

        with open('./start.js', 'r', encoding='utf-8') as f:
            js = execjs.compile(f.read())
        self.enctrack = js.call('get_encode_trace', self.slide_track, self.s)
        self.pass_time = self.slide_track[-1][-1]

        # print(f"slide_track: {self.slide_track}")

    def ajax_php_more_content(self):
        """
        w3
        :return:
        """
        self.get_w3()
        # logger.info(f"w3: {self.w3}, len: {len(str(self.w3))}")
        url = "https://api.geevisit.com/ajax.php"
        params = {
            "gt": self.gt,
            "challenge": self.new_challenge,
            "lang": "zh-cn",
            "$_BCN": "0",
            "client_type": "web",
            "w": self.w3,
            "callback": "geetest_" + str(round(time.time() * 1000))
        }
        time.sleep(2.4)
        response = requests.get(url, headers=self.headers, params=params)
        print(response.text)
        if "validate" in response.text:
            logger.success(
                "验证成功, validate is {}".format(re.findall(r'"validate": "(.*)", "score"', response.text)[0]))

    def task_sequence(self):
        self.register_slide()
        self.gettype()
        self.get_php()
        self.ajax_php()
        self.get_php_more_content()
        self.ajax_php_more_content()

    def main(self):
        self.read_js()
        tasks = []
        with ProcessPoolExecutor(max_workers=2) as executor:
            for _ in range(20):
                tasks.append(executor.submit(self.task_sequence))

        for task in tasks:
            task.result()


if __name__ == "__main__":
    GeetestSlide().main()
